﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Text;

namespace Beeline {
	class Beeline {

		public static string Parse(string UriQuery){
			BeelineEngine engine = new BeelineEngine(UriQuery);
			return engine.Parse(UriQuery);
		}

		public string ParseTokens(BeelineEngine Engine,string[] Tokens){
			return String.Format(Engine.URL,String.Join(" ",Tokens));
		}
	}

	public class BeelineEngine {
		public string Name { get; set; }
		public string Keyword { get; set; }
		public string URL { get; set; }
		public int Status { get; set; }
		public string Description { get; set; }
		public bool PlusSpaces { get { return ((Status & (int)Options.PlusSpaces)==(int)Options.PlusSpaces); } }

		public enum Options {
			PlusSpaces = 1
		}
		
		private object[] TokenizeQuery(string Query){
			string UriQuery = System.Uri.UnescapeDataString(Query);
			if(UriQuery.StartsWith("/")){ UriQuery = UriQuery.Substring(1); }
			string[] keys = (UriQuery.Substring(0,UriQuery.IndexOf(" "))).Trim().Split(Convert.ToChar("/"));
			string[] tokens = UriQuery.Substring(UriQuery.IndexOf(" ")).Trim().Split(Convert.ToChar(" "));
			return new object[]{ keys,tokens };
		}

		public string Parse(string Query){
			object[] tokenized = TokenizeQuery(Query);
			string[] tokens = (string[])tokenized[1];
			string[] commands = (string[])tokenized[0];

			string command = commands.Length>0?commands[commands.Length-1]:commands[0];

			string query = System.Uri.EscapeUriString(String.Join(" ",tokens));
			if(PlusSpaces){ query = query.Replace("%20","+"); }

			// Default response (YubNub)
			if(String.IsNullOrEmpty(this.URL)){
				return String.Format("http://www.yubnub.org/parser/parse?command={0}+{1}",command,query);
			}
			else {
				return String.Format(this.URL, query);
			}
		}

		private DataSet CreateSampleDataSet(){
			DataSet sample = new DataSet("Beeline");

			DataTable engineTable = new DataTable("Engine");
			engineTable.Columns.AddRange(new DataColumn[]{
				new DataColumn("Name"),
				new DataColumn("Keyword"),
				new DataColumn("URL"),
				new DataColumn("Status"),
				new DataColumn("Description")
			});

			engineTable.Rows.Add(new object[] {
				"Google",
				"g",
				"http://www.google.com/search?q={0}",
				0,
				"Standard Google search."
			});

			engineTable.Rows.Add(new object[] {
				"Google Australia",
				"ga",
				"http://www.google.com.au/search?q={0}",
				0,
				"Standard Google Australia search."
			});

			sample.Tables.Add(engineTable);
			return sample;
		}

		public BeelineEngine(string Query){

			object[] tokenized = TokenizeQuery(Query);
			string[] tokens = (string[])tokenized[1];
			string[] commands = (string[])tokenized[0];

			string command = commands.Length>0?commands[commands.Length-1]:commands[0];
			string query = String.Join(" ",tokens);

			string configFile = DiscoverFile("BeelineEngines.xml");
			DataTable engineTable = null;
			// Create a sample set:
			if(String.IsNullOrEmpty(configFile)){
				DataSet sample = CreateSampleDataSet();
				engineTable = sample.Tables["Engine"];
				string programFolder = Path.Combine(ProgramFilesx86(),"Beeline");
				if(!Directory.Exists(programFolder)){
					try { Directory.CreateDirectory(programFolder); }
					catch(Exception err) {
						if(EventLog.SourceExists("Beeline")){
							EventLog.WriteEntry("Beeline", err.ToString());
						}
					}
				}
				try {
					sample.WriteXml(Path.Combine(programFolder,"BeelineEngines.xml"));
				}
				catch(Exception err) {
					if(EventLog.SourceExists("Beeline")){
						EventLog.WriteEntry("Beeline", err.ToString());
					}
				}
			}
			else {
				DataSet dataset = new DataSet();
				dataset.ReadXml(configFile);
				engineTable = dataset.Tables["Engine"];
			}
			
			// Query for key/command
			if(engineTable!=null){
				DataRow[] searchResults = engineTable.Select(String.Format("Keyword='{0}'",command));
				if(searchResults.Length>0){
					object[] item = searchResults[0].ItemArray;
					this.Name = (string)item[0];
					this.Keyword = (string)item[1];
					this.URL = (string)item[2];
					this.Status = Convert.ToInt32((string)item[3]);
					this.Description = (string)item[4];
				}
			}
			else {
				if(EventLog.SourceExists("Beeline")){
					EventLog.WriteEntry("Beeline", "Could not create or load an engine list.");
				}
			}

		}

		public static string DiscoverFile(string Filename) {
			List<string> Paths = PathList();
			foreach(string path in Paths.ToArray<string>()) {
				if(File.Exists(Path.Combine(path, Filename))) {
					return Path.Combine(path, Filename);
				}
			}
			return String.Empty;
		}

		private static List<string> PathList(){
			List<string> pathList = new List<string>();
			pathList.Add(Path.Combine(ProgramFilesx86(),"Beeline"));
			if(!String.IsNullOrEmpty(System.Environment.GetEnvironmentVariable("PATH"))) {
				string[] paths = System.Environment.GetEnvironmentVariable("PATH").Split(Convert.ToChar(";"));
				pathList.AddRange(paths);
			}
			return pathList;
		}

		private static string ProgramFilesx86()
    {
        if( 8 == IntPtr.Size 
            || (!String.IsNullOrEmpty(Environment.GetEnvironmentVariable("PROCESSOR_ARCHITEW6432"))))
        {
            return Environment.GetEnvironmentVariable("ProgramFiles(x86)");
        }

        return Environment.GetEnvironmentVariable("ProgramFiles");
    }
	}

}
